/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package GameObject;

import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.image.BufferedImage;
import java.util.ArrayList;

/**
 *
 * @author Huy
 */
public final class Map {

	int landColor = 0x00006000;
	int seaColor = 0x00000060;
	TilledMap terrainMap;
	private int[][] terrainMatrix;
	private int[][] itemMatrix;
	BufferedImage miniMap;
	int landLevel;

	public Map(BufferedImage res, int col, int row, int[][] matrix, int landLevel) {
		terrainMatrix = matrix;
		terrainMap = new TilledMap(res, col, row, matrix);
		itemMatrix = new int[terrainMap.getMapRow()][terrainMap.getMapCol()];
		initItemMatrix();
		this.landLevel = landLevel;
		int h = matrix.length;
		int w = matrix[0].length;
		miniMap = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
		for (int i = 0; i < h; i++) {
			for (int j = 0; j < w; j++) {
				if (matrix[i][j] < landLevel) {
					miniMap.setRGB(j, i, seaColor);
				} else {
					miniMap.setRGB(j, i, landColor);
				}
			}
		}
	}

	public void initItemMatrix() {
		for (int i = 0; i < terrainMap.getMapRow(); i++) {
			for (int j = 0; j < terrainMap.getMapCol(); j++) {
				itemMatrix[i][j] = -1;
			}
		}
	}

	public int getMapCol() {
		return terrainMap.getMapCol();
	}

	public int getMapRow() {
		return terrainMap.getMapRow();
	}

	public int getCellWidth() {
		return terrainMap.getCellWidth();
	}

	public int getCellHeight() {
		return terrainMap.getCellHeight();
	}

	public int getX() {
		return terrainMap.getPosition().x;
	}

	public int getY() {
		return terrainMap.getPosition().y;
	}

	public int getWidth() {
		return terrainMap.getWidth();
	}

	public int getHeight() {
		return terrainMap.getHeight();
	}

	public BufferedImage getTinyMap() {
		return miniMap;
	}

	public void draw(Graphics2D g) {
		terrainMap.draw(g);
	}

	public void draw(Graphics2D g, int dx, int dy) {
		terrainMap.draw(g, dx, dy);
	}

	public boolean isLand(int i, int j) {
		if (i < 0 || i > getMapRow() || j < 0 || j > getMapCol()) {
			return false;
		}
		return terrainMap.getMatrix(i, j) >= landLevel;
	}

	public boolean isBuildAble(int i, int j) {
		if (i < 0 || i > getMapRow()-1 || j < 1 || j > getMapCol()-1) {
			return false;
		}
		return (terrainMap.getMatrix(i, j) >= landLevel && itemMatrix[i][j] == -1);
	}

	public void addItem(int i, int j, int n) {
		itemMatrix[i][j] = n;
	}

	public int getItem(int i, int j) {
		return itemMatrix[i][j];
	}

	public ArrayList<Point> getPath(int is, int js, int it, int jt) {

		int n = getMapRow();
		int m = getMapCol();
		ArrayList<Point> v = null;


		int[][] cost = new int[n][m];
		int[][] dir = new int[n][m];
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < m; j++) {
				dir[i][j] = -1;
				cost[i][j] = -1;
			}
		}
		v.add(new Point(it, jt));
		cost[it][jt] = 0;
		Point target = new Point(is, js);
		while (!v.get(0).equals(target)) {

			int ic = v.get(0).x;
			int jc = v.get(0).y;
			v.remove(0);
			int c = cost[ic][jc];
			for (int d = 0; d < 8; d++) {
				int cn = getMoveCost(ic, jc, d);

				if (cn != -1) {
					int in = ic + di[d];
					int jn = jc + dj[d];
					//int cn = c + getHeristic(ic, jc, in, jn);
					int hn = c + getHeristic(in, jn, is, js);
					int co = cost[in][jn];

					if (co == -1 || co > cn) {
						dir[in][jn] = d;
						cost[in][jn] = cn;
						for (int k = 0; k < v.size(); k++) {
							int x = v.get(k).x;
							int y = v.get(k).y;
							int g = cost[x][y] + getHeristic(x, y, is, js);
							if (cn + hn <= g) {
								v.add(k, new Point(in, jn));
							}
						}
					}
				}
			}
			if (v.isEmpty()) {
				return new ArrayList<Point>();
			}
		}

		ArrayList<Point> path = new ArrayList<Point>();
		int xc = is;
		int yc = js;
		int dLast = dir[xc][yc];
		int d = dLast;
		while (xc != it || yc != jt) {
			xc -= di[d];
			yc -= dj[d];
			d = dir[xc][yc];
			if (dLast != d) {
				path.add(new Point(xc, yc));
				dLast = d;
			}
		}
		path.add(new Point(it, jt));
		return path;

	}
	int[] di = new int[]{1, 0, -1, -1, -1, 0, 1, 1, 1, 0};
	int[] dj = new int[]{1, 1, 1, 0, -1, -1, -1, 0, 1, 1};

	private int getMoveCost(int i, int j, int d) {
		int s = 2 * (getMapRow() + getMapCol());
		int in = i + di[d];
		int jn = j + dj[d];
		if (in < 0 || in >= getMapRow() || jn < 0 || jn >= getMapCol()) {
			return -1;
		}
		int cost = getHeristic(i, j, in, jn);
		if (terrainMatrix[in][jn] < landLevel) {
			return cost * s;
		} else if (d % 2 == 1) {
			if (terrainMatrix[i + di[d - 1]][j + dj[d - 1]] < landLevel
					|| terrainMatrix[i + di[d + 1]][j + dj[d + 1]] < landLevel) {
				return cost * s;
			}
		}
		return cost;
	}

	private int getHeristic(int xs, int ys, int xt, int yt) {
		return (xs - xt) * (xs - xt) + (ys - yt) * (ys - yt);
	}

	public static int[][] text2Matrix(String t) {
		int[][] matrix;
		String[] rows = t.trim().split("\n");
		matrix = new int[rows.length][];
		for (int i = 0; i < rows.length; i++) {
			String[] cells = rows[i].trim().split(" ");
			matrix[i] = new int[cells.length];
			for (int j = 0; j < cells.length; j++) {
				try {
					int value = Integer.valueOf(cells[j]);
					matrix[i][j] = value;
				} catch (Exception e) {
					// TODO: handle exception
				}
			}
		}
		return matrix;

	}

	public static int[][] image2Matrix(BufferedImage img, int maxFrame) {

		int h = img.getHeight();
		int w = img.getWidth();
		int[][] matrix = new int[h][w];

		for (int i = 0; i < h; i++) {
			for (int j = 0; j < w; j++) {
				int color = img.getRGB(j, i);
				int red = (color & 0x00ff0000) >> 16;
				int green = (color & 0x0000ff00) >> 8;
				int blue = color & 0x000000ff;
				matrix[i][j] = ((red + green + blue) * maxFrame) / (3 * 256);
			}
		}
		return matrix;

	}

	public static int[][] createMatrix(int w, int h, int level, int minLevel, int maxLevel, Point[] p) {
		int[][] matrix = new int[h][w];
		for (int i = 0; i < h; i++) {
			for (int j = 0; j < w; j++) {
				matrix[i][j] = minLevel;
			}
		}
		for (int i = 0; i < 100 + w / 5; i++) {
			for (int j = 0; j < p.length; j++) {
				int r = (int) (Math.random() * (level - level * i / w));
				int x = p[j].x + (int) (Math.random() * level * 2) - level;
				int y = p[j].y + (int) (Math.random() * level * 2) - level;
				for (int m = x - r; m < x + r + 1; m++) {
					for (int n = y - r; n < y + r + 1; n++) {
						if (m >= 0 && m < w
								&& n >= 0 && n < h
								&& matrix[n][m] < maxLevel
								&& (m - x) * (m - x) + (n - y) * (n - y) <= r * r) {
							matrix[n][m]++;
						}
					}
				}
				for (int m = p[j].x - 2; m < p[j].x + 2; m++) {
					for (int n = p[j].y - 2; n < p[j].y + 2; n++) {
						matrix[n][m] = maxLevel;
					}
				}

			}
		}
		return matrix;
	}
}
